// Simple graph visualization using vis-network
const container = document.getElementById('network');
let network;
let allNodesData = [];
let allEdgesData = [];
let adjacency = new Map(); // csvId -> Set of neighbor ids

async function loadGraph() {
  const resp = await fetch('/api/graph/all');
  const data = await resp.json();
  const nodes = new vis.DataSet(data.nodes.map(n => ({
    id: n.id,
    label: n.label,
    title: n.alias,
    shape: 'circle'
  })));
  const edges = new vis.DataSet(data.edges.map(e => ({
    from: e.from,
    to: e.to,
    label: e.label,
    arrows: {to: {enabled: true, scaleFactor: 1.5}}, // 放大箭头
    length: 200 // 调整线条物理长度，值越大越长
  })));

  // 生成邻接表用于后续过滤
  adjacency.clear();
  edges.forEach(e => {
    if (!adjacency.has(e.from)) adjacency.set(e.from, new Set());
    adjacency.get(e.from).add(e.to);
    if (!adjacency.has(e.to)) adjacency.set(e.to, new Set());
    adjacency.get(e.to).add(e.from); // 方便双向查找
  });

  // 备份完整数据，便于还原
  allNodesData = nodes.get();
  allEdgesData = edges.get();
  const options = { 
    nodes: {
      shape: 'circle',          // 圆形节点
      size: 30,                 // 半径
      color: {background: '#007bff', border: '#0056b3'},
      font: {color: '#ffffff', size: 16, face: 'sans-serif', vadjust: 0}
    },
    edges: {
      font: {align: 'middle'},
      color: '#848484',
      arrows: {to: {enabled: true, scaleFactor: 1.5}} // 全局箭头放大
    },
    interaction: {hover: true},
    physics: {
      barnesHut: {
        springLength: 200,
        springConstant: 0.02
      },
      stabilization: false
    }
  };
  network = new vis.Network(container, {nodes, edges}, options);

  // 双击节点：仅保留该节点及直接相连节点 / 边
  network.on('doubleClick', params => {
    if (params.nodes.length) {
      const id = params.nodes[0];
      const idsToShow = new Set([id]);
      const neighborSet = adjacency.get(id);
      if (neighborSet) {
        neighborSet.forEach(n => idsToShow.add(n));
      }
      const filteredNodes = allNodesData.filter(n => idsToShow.has(n.id));
      const filteredEdges = allEdgesData.filter(e => idsToShow.has(e.from) && idsToShow.has(e.to));

      network.setData({
        nodes: new vis.DataSet(filteredNodes),
        edges: new vis.DataSet(filteredEdges)
      });
    } else {
      // 双击空白区域恢复全图
      network.setData({
        nodes: new vis.DataSet(allNodesData),
        edges: new vis.DataSet(allEdgesData)
      });
    }
  });

  network.on('click', async params => {
    if (params.nodes.length) {
      const id = params.nodes[0];
      const res = await fetch('/api/person/' + id);
      if (res.ok) {
        const detail = await res.json();
        showDetail(detail);
      }
    }
  });
}

function showDetail(detail) {
  const div = document.getElementById('detail');
  div.innerHTML = `<h3>${detail.name}</h3><p>${detail.alias || ''}</p>
    <button id="btnAddRel">新增关系</button>
    <button id="btnAddNodeRel">新增节点并关系</button>
    <button id="btnUploadMedia">上传媒体</button>
    <button id="btnDeleteNode">删除节点</button>
    <button id="btnShowMedia">详情</button>`;
  div.classList.remove('hidden');

  // 上传媒体按钮
  document.getElementById('btnUploadMedia').onclick = () => {
    const back = document.getElementById('uploadBackdrop');
    back.classList.remove('hidden');

    document.getElementById('uplType').value = 'image';
    document.getElementById('uplTitle').value = '';
    document.getElementById('uplDesc').value = '';
    document.getElementById('uplFile').value = '';

    const close = () => back.classList.add('hidden');
    document.getElementById('btnUplCancel').onclick = close;

    document.getElementById('btnUplOk').onclick = async () => {
      const type = document.getElementById('uplType').value;
      const title = document.getElementById('uplTitle').value.trim();
      const desc = document.getElementById('uplDesc').value.trim();
      const file = document.getElementById('uplFile').files[0];
      if (!file || !title) { alert('文件和标题必填'); return; }

      const form = new FormData();
      form.append('file', file);
      form.append('csvId', detail.csvId);
      form.append('type', type);
      form.append('title', title);
      form.append('description', desc);

      const res = await fetch('/api/media/upload', {method:'POST', body:form});
      if (res.ok) {
        alert('上传成功');
        close();
        loadGraph();
      } else {
        alert('上传失败: ' + await res.text());
      }
    };
  };

  // 删除节点
  document.getElementById('btnDeleteNode').onclick = async () => {
    if (!confirm('确定删除该节点?')) return;
    const res = await fetch('/api/graph/person/' + detail.csvId, {method:'DELETE'});
    if (res.ok) {
      alert('已删除');
      div.classList.add('hidden');
      loadGraph();
    } else {
      alert('删除失败: ' + await res.text());
    }
  };

  // 展示媒体详情
  document.getElementById('btnShowMedia').onclick = () => {
    // 移除旧的媒体展示块
    const old = document.getElementById('mediaBox');
    if (old) old.remove();

    let html = '<div id="mediaBox"><h4>媒体详情</h4>';
    if (detail.videos && detail.videos.length) {
      const validVideos = detail.videos.filter(v => v.videoFileId);
      if (validVideos.length) {
        html += '<h5>视频</h5>';
        validVideos.forEach(v => {
          html += `<video src="/api/file/${v.videoFileId}" controls width="250"></video><p>${v.title}</p>`;
        });
      }
    }
    if (detail.images && detail.images.length) {
      const validImgs = detail.images.filter(img => img.fileId);
      if (validImgs.length) {
        html += '<h5>图片</h5>';
        validImgs.forEach(img => {
          html += `<img src="/api/file/${img.fileId}" width="100" /><p>${img.title}</p>`;
        });
      }
    }
    if (detail.texts && detail.texts.length) {
      html += '<h5>文本</h5>';
      detail.texts.forEach(t => {
        html += `<p><strong>${t.title}</strong></p><pre style="white-space:pre-wrap;max-height:120px;overflow:auto;">${t.content}</pre>`;
      });
    }
    if ((!detail.videos || !detail.videos.length) && (!detail.images || !detail.images.length) && (!detail.texts || !detail.texts.length)) {
      html += '<p>暂无媒体</p>';
    }
    html += '</div>';
    div.insertAdjacentHTML('beforeend', html);
  };

  document.getElementById('btnAddRel').onclick = async () => {
    const targetName = prompt('输入目标人物姓名');
    if (!targetName) return;
    const relType = prompt('输入关系类型');
    if (!relType) return;

    // 根据名字查询获取 csvId
    const res = await fetch('/api/person/name/' + encodeURIComponent(targetName.trim()));
    if (!res.ok) {
      alert('未找到姓名对应人物');
      return;
    }
    const targetDetail = await res.json();
    const targetId = targetDetail.csvId;

    fetch('/api/graph/relation', {
      method: 'POST',
      headers: {'Content-Type': 'application/json'},
      body: JSON.stringify({fromId: detail.csvId, toId: targetId, type: relType.trim()})
    }).then(r => r.ok ? r.text() : r.text().then(t=>Promise.reject(t)))
      .then(msg => {
        alert(msg);
        loadGraph();
      })
      .catch(err => alert('创建失败:' + err));
  };

  document.getElementById('btnAddNodeRel').onclick = async () => {
    // 显示模态框
    const backdrop = document.getElementById('modalBackdrop');
    backdrop.classList.remove('hidden');

    document.getElementById('inpId').value = '';
    document.getElementById('inpName').value = '';
    document.getElementById('inpAlias').value = '';
    document.getElementById('inpSpecies').value = '';
    document.getElementById('inpRel').value = '';

    const closeModal = () => backdrop.classList.add('hidden');

    document.getElementById('btnModalCancel').onclick = closeModal;

    document.getElementById('btnModalOk').onclick = async () => {
      const newCsvId = Number(document.getElementById('inpId').value);
      const name = document.getElementById('inpName').value.trim();
      const alias = document.getElementById('inpAlias').value.trim();
      const species = document.getElementById('inpSpecies').value.trim();
      const relType = document.getElementById('inpRel').value.trim();
      if (!newCsvId || !name || !relType) {
        alert('id / 姓名 / 关系类型 不能为空');
        return;
      }

      // 创建节点
      const createRes = await fetch('/api/graph/person', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({csvId: newCsvId, name, alias, species})
      });
      if (!createRes.ok) {
        const errMsg = await createRes.text();
        if (createRes.status === 409) {
          alert('csvId 已存在，不可重复');
        } else {
          alert('创建节点失败: ' + errMsg);
        }
        return;
      }

      // 创建关系
      const relRes = await fetch('/api/graph/relation', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({fromId: detail.csvId, toId: newCsvId, type: relType})
      });
      if (!relRes.ok) {
        alert('创建关系失败: ' + await relRes.text());
        return;
      }
      backdrop.classList.add('hidden'); // 关闭弹窗
      alert('节点及关系已创建');
      loadGraph();

      // 防止多次绑定，重置按钮事件
      document.getElementById('btnModalOk').onclick = null;
      document.getElementById('btnModalCancel').onclick = null;
    };
  };
}

document.getElementById('btnLoad').addEventListener('click', loadGraph);

document.getElementById('btnSearch').addEventListener('click', async () => {
  const name = document.getElementById('search').value.trim();
  if (!name) return;
  const res = await fetch('/api/person/name/' + encodeURIComponent(name));
  if (!res.ok) return;
  const detail = await res.json();
  if (network) {
    network.selectNodes([detail.csvId]);
    network.focus(detail.csvId, {scale: 1.5});
    showDetail(detail);
  }
});

// Auto load on page ready
loadGraph(); 
// 上传模式切换显示
const modeSel = document.getElementById('uploadMode');
const zipIn = document.getElementById('zipInput');
const charsIn = document.getElementById('csvChars');
const relsIn = document.getElementById('csvRels');

function toggleUploadInputs() {
  const isZip = modeSel.value === 'zip';
  zipIn.classList.toggle('hidden', !isZip);
  charsIn.classList.toggle('hidden', isZip);
  relsIn.classList.toggle('hidden', isZip);
  document.getElementById('labelChars').classList.toggle('hidden', isZip);
  document.getElementById('labelRels').classList.toggle('hidden', isZip);
}
modeSel.onchange = toggleUploadInputs;
toggleUploadInputs();

document.getElementById('btnUpload').addEventListener('click', async () => {
  if (modeSel.value === 'zip') {
    const file = zipIn.files[0];
    if (!file) { alert('请选择 zip 文件'); return; }
    const form = new FormData();
    form.append('zipFile', file);
    const res = await fetch('/api/media/batch', {method:'POST', body: form});
    if (res.ok) { alert('批量上传成功'); loadGraph(); }
    else { alert('上传失败: ' + await res.text()); }
  } else {
    const c = charsIn.files[0];
    const r = relsIn.files[0];
    if (!c || !r) { alert('请选择两张 CSV'); return; }
    const form = new FormData();
    form.append('characters', c);
    form.append('relations', r);
    const res = await fetch('/api/import/upload', {method:'POST', body: form});
    if (res.ok) { alert('CSV 上传成功'); loadGraph(); }
    else { alert('上传失败: ' + await res.text()); }
  }
}); 